// this file is about recognation of game object at server side
#ifndef __SERVERGAMEOBJ__
#define __SERVERGAMEOBJ__
#include "wrap_direct3dcubetexture9.h"
#include "wrap_direct3dindexbuffer9.h"
#include "wrap_direct3dtexture9.h"
#include "wrap_direct3dvertexshader9.h"
#include "wrap_direct3dvertexdeclaration9.h"
#include "wrap_direct3dvertexbuffer9.h"
#include "wrap_direct3ddevice9.h"
#include <vector>
#include <map>
using namespace std;

#define UNKNOWN 0
#define CMD 1  // new cmd stream
#define DATA 2  // new data package
#define UPDATECMD 3  // updata the cmd parameters, format { offset to start, length}
#define UPDATADATA 4 // update data,  { offset to start, length}

class BaseObj{
	//int id;
	__int64 interval; ///
	__int64 lastUsed;  // record the time since last used
	unsigned char head;
	int objId;   // object id for the object
	static HashSet objecList;
public:
	
	char * renderSequence;  // cmd sequence for rendering
	static int ins_count;
	
	virtual void addBaseObj(BaseObj * obj);
	virtual BaseObj * getObj(int id); // get the obj with id
	virtual bool removeObj(BaseObj * obj);
	virtual bool removeObj(int id);// remove the obj with id

	void setHead(unsigned char _head);
	void setObjId(unsigned char _objId);
	void setRenderSequence(char * se);
	virtual void SendObj();
	BaseObj();
	BaseObj(int id);
	~BaseObj();
	
};

class ObjSamplerState:public BaseObj{
	int samplerCount;
	char * data;  // formated stage ( uchar), TYPE(uchar ), Value (dword)
};
class ObjTexture:public BaseObj{
	
	ObjSamplerState * samplers;

public:
	ObjTexture(int id);
};
class ObjRenderState:public BaseObj{

public:
	ObjRenderState(int id);

};
class ObjMesh:public BaseObj{

public:
	ObjMesh(int id);

};
class ObjVS:public BaseObj{

public:
	ObjVS(int id);

};
class ObjPS:public BaseObj{

public: 
	ObjPS(int id);

};
class ObjVSConstant:public BaseObj{
	union{
		float * F;
		BOOL * B;
		INT * I;
	}constantP;
public:
	ObjVSConstant(int id);
	~ObjVSConstant();
};

struct StreamDetail{
	int streamIndex;
	unsigned short usageTag; // each bit stands for a type of usage
	// indecate that normal is valid when bit 1 set, tangent valid bit 2, position valid bit 3, texture valid bit 4
	short n_off, n_size, t_off, t_size,p_off, p_size;
	short stideSize;
	short texCount;
	short *tex_off, *tex_size;
	short tt_off, tt_size; // total size of texture

	short c_off, c_size;
	
	bool n_valid, t_valid, tex_valid, p_valid, c_valid;
	short streamOff;
	

	// vertex buffer for the stream
	WrapperDirect3DVertexBuffer9 * svb;

	StreamDetail(){
		streamIndex= -1;
	}
	StreamDetail(int _stream){
		Log::log("StreamDetail constructor called, stream:%d\n",_stream);
		streamIndex= _stream;
		streamOff = -1;
		n_valid = false, t_valid = false, tex_valid = false, p_valid = false, c_valid = false;
		tt_off = 0, tt_size = 0, n_off = 0, n_size = 0, t_size = 0, p_off = 0, p_size =0;
	}
	~StreamDetail(){
		n_valid = false;
		t_valid= false;
		tex_valid = false;
		p_valid = false;

		streamIndex= -1;
		if(tex_off)
			delete tex_off;
		if(tex_size)
			delete tex_size;

	}
};

// draw unit, include vb, ib, vdeclaration, texture ,etc.
// identified by vb id and ib id
class GameObj:public BaseObj{
private:
	int id;

	DWORD FVF;
	bool fvfValid;
	
	int streamCount;
	WrapperDirect3DIndexBuffer9 * ib;  // index buffer

	//multi streams need multi vb and stride
	//WrapperDirect3DVertexBuffer9 ** vb_list;  // vertex buffer
	//int * stride_list; /// stride size for each Stream
	
	WrapperDirect3DVertexDeclaration9 * vd; // vertex declaration
	// the following two are the detail data for vertex declaration
	//D3DVERTEXELEMENT9 *pDecl;
	//UINT NumElements;

	

	ObjVSConstant *vsc;
	ObjRenderState * rs;

public:
	StreamDetail ** sd;
	static HashSet gameObjWithIIdList;
	static HashSet gameObjWithVIdList;  // vb for stream 0 will indentify the game object;

	int getStreamCount(){
		return streamCount;
	}
	GameObj();
	GameObj(int _StreamCount);
	~GameObj();

	int getId(){
		return id;
	}
	void setId();
	bool compressVB();
	bool compressVB(int lod); // compress vb with lod
	bool updateData();   //called before gameobject
	// getter and setter
	void setIB(WrapperDirect3DIndexBuffer9 * ib);
	WrapperDirect3DIndexBuffer9 * getIB();
	void setVB(WrapperDirect3DVertexBuffer9 * vb);
	WrapperDirect3DVertexBuffer9 * getVB(int stream);

	void setVB(int stream, WrapperDirect3DVertexBuffer9 * vb);
	void setVB(int stream, WrapperDirect3DVertexBuffer9 * vb, int _stream);

	void setObjVSConstant(ObjVSConstant * vsc);
	ObjRenderState * getObjRenderState();

	void setVD(WrapperDirect3DVertexDeclaration9 * vd);
	WrapperDirect3DVertexDeclaration9 * getVD();

	void setFVF(DWORD FVF);
	DWORD getFVF();

	int getNormalOff();
	int getTangetOff();
	int getTexOff();
	int getPositionOff();

	// parent's function
	void SendObj();
	void addBaseObj(BaseObj * obj);
	void addGameObj(GameObj * obj);
	void addGameObj(GameObj * obj , int vid);
	BaseObj * getObj(int id); // get the obj with id
	bool removeObj(BaseObj * obj);
	bool removeObj(int id);// remove the obj with id

	// decimate method
	bool decimateMesh(float ratioTo);
	
	// get gameobject from indexbufferid list with an index buffer idx 
	static GameObj * getGameObjWithIId(int iid);
	static GameObj * getGameObjWithVId(int vid);


	// prepare vertex data
	bool PrepareVertexBuffer(WrapperDirect3DVertexBuffer9 * wvb);
};


// object manager is a factory, managering creation and destroy
// only one manager and globaled
class SObjectManager{
private:
	// attribute
	int totalGameObj;
	vector<GameObj *> gameObjs;
	map<int ,int> VBMap;
	map< int , int > IBMap;

	GameObj * curObj; // this is the temp GameObject
	// function
	SObjectManager();

public:
	~SObjectManager();
	static SObjectManager* getObjManager();
	GameObj * getGameObjByVB(int id);
	GameObj * getGameObjByIB(int id);
	bool addGameObj(GameObj * obj);
	void setCurrentObj();
	GameObj * getCurrentObj();
	void addCurrentObj();

	
};


DWORD compressNormalToDword(float f1, float f2, float f3);
DWORD compressTangendToDword(float f1, float f2, float f3, float f4);
DWORD compressPositionToDword(float f1, float f2,float f3,float m1, float m2, float m3);

BYTE compressFloatToByte(float f1);
BYTE compressFloatToByte(float f1, float mod);

#endif
